/*!
 * Image Zoomer
 * 
 * @version 1.2 (2011.04.15) 설정 파일을 DOM 방식으로도 가능하도록 변경
 * @version 1.1 (2011.02.28) 프레임의 좌우 높이가 달라도 작동하도록 변경
 * @author ohgyun (ohgyun@gmail.com)
 */
(function() {
	/*
	 * [Prefix]
	 * t : text
	 * f : frame
	 * sf : small frame
	 * lf : large frame
	 * bf : bottom frame
	 * tb : thumb
	 * w : width
	 * h : height
	 * b : border
	 * bg: background color
	 * c : color
	 * ld : loading
	 * crnt : current
	 * othr : other
	 */
	var defaultConfig = {
		cT: "#41627e",
		wSf: 350,
		hSf: 500,
		wLf: 350,
		hLf: 500,
		bgcF: "#eee",
		bcF: "#999",
		hBf: 30,
		bgcBf: "#eee",
		bcTb: "#151b8d",
		ldT: "Loading...",
		bgcCrnt: "#666",
		bgcOthr: "#ccc",
		style: ""
	};
	
	var c,
		config = defaultConfig,
		siteConfig = this.$izs.config || {}; // $izs(image-zoomer.site.js에 정의)
	for (c in siteConfig) { config[c] = siteConfig[c]; }
	
	function preloadImage(images) {
		for (var i = 0; i < images.length; i++) {
			(new Image()).src = images[i].small;
			(new Image()).src = images[i].large;
		}
	}
	
	/**
	 * Image Zoomer
	 * 
	 * @param {Object} images
	 */
	var ImageZoomer = this.IZ = {
		// 연속하여 IZ.load()를 호출하게 되면 현재 이미지가 로드 중 이전 다운로드 중이던
		// 이미지의 load 이벤트가 발생할 가능성이 있다. 이 때, 이미지 load 이벤트에 대한
		// 컨트롤은 불가능하기 때문에 이전 이미지에 대한 콜백이 발생한다. 이와 같은 경우를
		// 방지하고 현재 이미지에 대한 콜백만 처리하기 위해 현재 요청에 대한 고유한 키를 둔다.
		_jobKey: 0,
			
		init: function(images) {
			$izs.defineStyle(config, images);
			$izs.createDom(config, images);
			
			preloadImage(images);
			ImageZoomer.initArea();		
			
			$(document).ready(function() {
				// document가 준비되면 첫 번째 이미지를 로드한다.
				ImageZoomer.loadFirstImage(images);
			});
		},
		
		initArea: function() {
			Small.init();
			Large.init();
			Thumb.init();
			Bottom.init();
		},
		
		loadFirstImage: function(images) {
			ImageZoomer.load(images[0]);
		},
		
		// 일부 쇼핑몰의 경우, 상세설명 글에 스크립트 태그를 넣을 수 없다.
		// 이 경우엔 <div id="image-zoomer-config"><span class="url">xxx</span></div>와 같은 설정 태그를 본문에 추가하고,
		// 스크립트를 최상단에 넣고 initByDom을 호출한다.
		initByDom: function() {
			$(document).ready(function() {
				// document가 준비되면 image-zoomer-config .url 에서 주소를 읽어와 로드한다.
				var domConfig = $("#image-zoomer-config");
				if (domConfig.length === 0) {
					return;
				}
				
				var images = [];
				domConfig.find(".url").each(function() {
					var url = $.trim($(this).text());
					images.push({
						small: url,
						large: url
					});
				});
				
				$izs.appendStyleTag(config, images);
				$izs.appendDom(config, images, domConfig);
				$izs.fixLayoutIfNotSupportBoxModel(config);
				$izs.showImageZoomer();
				
				preloadImage(images);
				
				ImageZoomer.initArea();
				ImageZoomer.loadFirstImage(images);
			});
		},
		
		/**
		 * 이미지를 로드한다.
		 * 작은 이미지를 먼저 로드하고, 로드가 완료되면 큰 이미지를 로드한다.
		 * 큰 이미지 로드가 완료되면 Thumb를 셋팅한다.
		 * @param {Object} urls
		 */
		load: function(urls) {
			var currentKey = ++this._jobKey; 
			
			this.reset();
			
			Bottom.set(urls);
			Small.load(urls.small, function() {
				if (ImageZoomer.isNotCurrentJob(currentKey)) { return; }
				Large.load(urls.large, function(wRatio, hRatio) {
					if (ImageZoomer.isNotCurrentJob(currentKey)) { return; }
					Thumb.set(wRatio, hRatio);
				});
			});
		},
		
		isNotCurrentJob: function(key) {
			return key !== this._jobKey;
		},
		
		reset: function() {
			Small.reset();
			Large.reset();
			Thumb.reset();
			Bottom.reset();
		}
	};
	
	/**
	 * 좌측에 표시되는 작은 이미지.
	 * Large의 맵 역할을 하며, 크기는 프레임 크게 맞게 고정되어 있다.
	 */
	var Small = {
		_el: null,
		
		init: function() {
			this._el = $("#image-zoomer div.small");
		},
		
		load: function(url, callback) {
			var self = this;
			this._el.find("img")
					.load(function() {
						self._el.removeClass("small_loading");
						callback();
					})
					.click(function(event) {
						var offset = self._el.offset();
						var left = event.pageX - offset.left;
						var top = event.pageY - offset.top;
						
						Thumb.move(left, top, true);
					})
					.attr("src", url);
		},
		
		reset: function() {
			this._el.addClass("small_loading")
					.find("img")
					.attr("src", "");
		}
	};
	
	/**
	 * 우측에 표시되는 상세 이미지.
	 * 상세 이미지의 크기에 따라 Thumb의 사이즈가 결정된다.
	 */
	var Large = {
		_el: null, 
		
		init: function() {
			this._el = $("#image-zoomer div.large");
		},
		
		load: function(url, callback) {
			var self = this;
			var image = new Image();
			$(image)
				.load(function() {
					self._el.css("background-image", "url(" + this.src + ")")
								.removeClass("large_loading");
			
					callback(this.width, this.height);
				})
				.attr("src", url);				
		},
		
		move: function(left, top) {
			this._el.css("background-position", left + "px " + top + "px");
		},
		
		reset: function() {
			this._el.css("background-image", "none")
					.addClass("large_loading");
		}
	};
	
	/**
	 * 작은 이미지에 표시되는 드래그 할 수 있는 타겟.
	 * Small 내에서 드래그 가능하며, 이동 시 Large의 배경을 변경한다.
	 */
	var Thumb = {
		_el: null,
		_wRatio: 0,
		_hRatio: 0,
		_wTb: 0,
		_hTb: 0,
		
		init: function() {
			this._el = $("#image-zoomer div.thumb").draggable({
				containment: "parent"
			});
		},
		
		set: function(wImg, hImg) {
			// large frame과 실제 이미지와의 비율.
			// thumb의 크기와 thumb 이동 시 large가 움직이는 값의 기준이 된다.
			var wRatio = this._wRatio = wImg / config.wLf;
			var hRatio = this._hRatio = hImg / config.hLf;
			
			// Thumb의 크기 계산법
			// 		thumb : small frame = large frame : image
			// 		thumb = small frame * large frame / image
			var wTb = this._wTb = config.wSf / wRatio;
			var hTb = this._hTb = config.hSf / hRatio;
	
			var self = this;
			this._el.css("width", wTb + "px")
					.css("height", hTb + "px")
					.css("display", "block")
					.bind("drag", function(event, ui) {
						self.move(ui.position.left, ui.position.top, false);
					});
					
			// 최초 로드 시 이미지의 중심이 확대되도록 한다.
			this.move(config.wSf/2, config.hSf/2, true);
		},
		
		/**
		 * 해당 포인트로 Thumb를 이동한다.
		 * 
		 * @param {Object} left 클릭한 좌표
		 * @param {Object} top
		 * @param {Boolean} moveThumb thumb를 이동할 것인가? 클릭 이벤트에 의해 발생하는 경우
		 */
		move: function(left, top, moveThumb) {
			if (moveThumb) {
				// Small에서 발생한 클릭 이벤트에 의해 Thumb를 이동해야 하는 경우.
				// 드래그 할 경우, 드래그 영역의 제한은 Draggable에서 처리하므로
				// 영역 제한은 moveThumb가 true일 때에만 처리한다. 

				// 위치를 thumb의 중심으로 이동한다. 
				left = left - this._wTb/2;
				top = top - this._hTb/2;
				
				// 좌측, 상단에 대한 제한
				if (left < 0) left = 0;
				if (top < 0) top = 0;

				// 우측, 하단에 대한 제한
				var wLimit = config.wSf - this._wTb;
				var hLimit = config.hSf - this._hTb;
				if (left > wLimit) left = wLimit;
				if (top > hLimit) top = hLimit;
				
				this._el.css("left", left + "px")
						.css("top", top + "px");
			}
			
			// Large의 background-position을 이동한다.
			// wImg/wLf 비율에 wLf/wSf의 비율을 곱한다.
			var bgLeft = - (left * this._wRatio * config.wLf/config.wSf);
			var bgTop = - (top * this._hRatio * config.hLf/config.hSf);
			
			Large.move(bgLeft, bgTop);
		},
		
		reset: function() {
			this._el.css("display", "none")
					.unbind("drag");
		}
	};
	
	/**
	 * 하단에 표시되는 영역.
	 * 이전/다음 이미지로 전환하는 역할을 한다.
	 */
	var Bottom = {
		_el: null,
		
		init: function() {
			this._el = $("#image-zoomer div.bottom").delegate("a", "click", function() {
				var t = $(this);
				var urls = {
					small: t.attr("small-url"),
					large: t.attr("large-url")
				};
				
				ImageZoomer.load(urls);
				
				return false;
			});
		},
		
		set: function(urls) {
			this._el.find("a[small-url='" + urls.small + "']").addClass("current");
		},
		
		reset: function() {
			this._el.find("a").removeClass("current");
		}
	};
	
	(function() {
		// IE6 Background Image Flicker Bug Fix
		try { document.execCommand('BackgroundImageCache', false, true); } catch(e) {}
	})();
})();